﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using octopus_project.enumeration;
using octopus_project.scene;
using octopus_project.screen;
using octopus_project.util;
using octopus_project.scene.build;
using octopus_project.typegame;
using octopus_project.tileset.mapCells;

namespace octopus_project.tileset {

    class TileMap_GameplayEntry : GameplayEntry {

        private List<MapRow> Rows = new List<MapRow>();

        /// <summary>
        /// Description.
        /// </summary>
        public TileMap_GameplayEntry(GameScreen gameScreen) : base(gameScreen) {

            for (int y = 0; y < Constant.TOTAL_TILES_Y; y++) {
                MapRow thisRow = new MapRow();

                for (int x = 0; x < Constant.TOTAL_TILES_X; x++) {
                    thisRow.Columns.Add(new NotConquered_MapCell());
                }

                Rows.Add(thisRow);
            }
        }

        /// <summary>
        /// Description.
        /// </summary>
        public TileMap_GameplayEntry(GameScreen gameScreen, String csvFilePath) : base(gameScreen) {

            List<string[]> parsedData = CSVParser.parseCSV(csvFilePath);

            if (parsedData.Count != Constant.TOTAL_TILES_Y) {
                Console.Write("Missing data in the X axis");
                return;
            }

            foreach (string[] aStringArray in parsedData) {
                MapRow thisRow = new MapRow();
                byte cellByte;
                foreach (string aString in aStringArray) {
                    if (aStringArray.Length != Constant.TOTAL_TILES_X) {
                        Console.Write("Missing data in the Y axis");
                        return;
                    }
                    cellByte = Byte.Parse(aString);
                    MapCell mapCell = MapCell.createMapCell(TileTypeExtensions.getFromValue(cellByte));
                    mapCell.x = thisRow.Columns.Count;
                    mapCell.y = Rows.Count;
                    //mapCell.castle = TileTypeExtensions.isCastle(mapCell.tileType);

                    thisRow.Columns.Add(mapCell);
                }
                
                Rows.Add(thisRow);
            }
        }

        public override void Update () {
            
        }

        /// <summary>
        /// Description.
        /// </summary>
        public override void Draw() {
            MapCell aMapCell;
            
            spriteBatch.Begin();
            
            for (int y = 0; y < Constant.TOTAL_TILES_Y; y++) {
                for (int x = 0; x < Constant.TOTAL_TILES_X; x++) {
                    
                    aMapCell = getMapCell(x, y);

                    aMapCell.paint(spriteBatch, x, y, this);
                }
            }
            spriteBatch.End();

        }

        /// <summary>
        /// Description.
        /// </summary>
        public bool updateTileMap(Build_Cursor cursor, Player player) {
            bool wasUpdated = false;

            if(isLandPrepared(cursor)) {

                for(byte x = 0; x < cursor.CurrentTetrad.getCurrentShape().GetLength(0); x++) {
                    for(byte y = 0; y < cursor.CurrentTetrad.getCurrentShape().GetLength(1); y++) {

                        if(cursor.CurrentTetrad.getCurrentShape()[x, y] == 1) {

                            MapCell mapCell = getMapCell((cursor.PositionX + x), (cursor.PositionY + y));
                            mapCell.player = player;
                            mapCell.x = (cursor.PositionX + x);
                            mapCell.y = (cursor.PositionY + y);


                            Rows[(cursor.PositionY + y)].Columns[(cursor.PositionX + x)] = mapCell.build(); 
                            //setMapCell((cursor.PositionX + x), (cursor.PositionY + y), TileType.PLAYER_WALL, player);
                        }
                    }
                }

                wasUpdated = true;
            }
            else {
                wasUpdated = false;
            }

            return wasUpdated;
        }

        /// <summary>
        /// Se puede insertar un tetrad cuando es todo Wall o todo not-conquered
        /// </summary>
        private bool isLandPrepared(Build_Cursor cursor) {
            MapCell aMapCell;
            byte countMapCells = 0;
            byte countWalls = 0;

            for (byte x = 0; x < cursor.CurrentTetrad.getCurrentShape().GetLength(0); x++) {
                for (byte y = 0; y < cursor.CurrentTetrad.getCurrentShape().GetLength(1); y++) {

                    if (cursor.CurrentTetrad.getCurrentShape()[x, y] == 1) {
                        countMapCells++;

                        aMapCell = getMapCell((cursor.PositionX + x), (cursor.PositionY + y));

                         if (!aMapCell.isEnabledToBuild()) {
                           return false;
                        }
                        
                        if (aMapCell.tileType == TileType.PLAYER_WALL) {
                            countWalls++;
                        }
                    }
                }
            }
            //si no existe pared o si todos son pared
            if (countWalls == 0 || countWalls == countMapCells) {
                return true;
            }

            return false;
        }


        /// <summary>
        /// Description.
        /// </summary>
        public MapCell getMapCell(int column, int row) {
            if (column > -1 && row > -1)
                return Rows[row].Columns[column];
            else return null;
        }

        /// <summary>
        /// Description.
        /// </summary>
        public void setMapCell(int column, int row, TileType idTileCell, Player player) {
            MapCell mapCell = MapCell.createMapCell(idTileCell);
            mapCell.player = player;

            Rows[row].Columns[column] = mapCell;
            
        }
        /// <summary>
        /// Description.
        /// </summary>
        public void setMapCell(int column, int row, MapCell mapCell) {
            
            Rows[row].Columns[column] = mapCell;

        }
        /// <summary>
        /// Description.
        /// </summary>
        public MapCell replaceMapCell(int column, int row, MapCell mapCell) {
            
            MapCell mapCellOld = getMapCell(column, row);
            if(mapCellOld.tileType != TileType.PLAYER_CASTLE){
                mapCell.setValues(mapCellOld);

                Rows[row].Columns[column] = mapCell;
                return mapCell;

            }
            return mapCellOld;

        }

        /*public bool putCannon(Player player, int x, int y) {
            MapCell mapCell = getMapCell(x, y);

            if (mapCell.GetType().IsInstanceOfType(new Conquered_MapCell()) && player.Equals(mapCell.player)) {
                //intento de uso de objeto

                replaceMapCell(x, y, new MiniCannon_MapCell());

                return true;
            }
        */
            /*if (mapCell.conquered && player.Equals(mapCell.player) && mapCell.tileType != TileType.PLAYER_WALL && mapCell.tileType != TileType.PLAYER_MINI_CANNON && !mapCell.castle) {
                mapCell.tileType = TileType.PLAYER_MINI_CANNON;
                return true;
            }*/

     /*       return false;
        }*/

       /* public bool shootCannon(Player player, int x, int y) {
            MapCell mapCell = getMapCell(x, y);

            Rows[y].Columns[x] = mapCell.shootMe();
            //replaceMapCell(x,y,mapCell.shootMe());

            return true;
        }*/


        /// <summary>
        /// Description.
        /// </summary>
        private void check_conqueredAfterBuild() {
            
            List<MapCell> tilesToCheck = new List<MapCell>();
            
            //const int OWNER_NOONE = -1;
            int x, y;
            
            // initial pass
            for (y = 0; y < Constant.TOTAL_TILES_Y; y++)
                for (x = 0; x < Constant.TOTAL_TILES_X; x++) {

                    MapCell cell = firstCheck(x, y);
                    
                    if (cell != null) {
                        tilesToCheck.Add(cell);
                    }
                } // end initial pass


            secondCheck(tilesToCheck);

            
            //paintDiferentsPlayer(player);
        }//end check conquer


        public void cleanAfterWar() {
            /*List<MapCell> tilesArms = new List<MapCell>();
            
            int x, y;
            
            // initial pass
            for (y = 0; y < Constant.TOTAL_TILES_Y; y++) {
                for (x = 0; x < Constant.TOTAL_TILES_X; x++) {

                    MapCell mapCell = getMapCell(x, y);
                    
                    if (mapCell.tileType == TileType.PLAYER_MINI_CANNON) {
                        tilesArms.Add(mapCell);
                    }
                }
            }*/

            check_conqueredAfterBuild();
/*
            foreach (MapCell mapCell in tilesArms) {
                if (this.getMapCell(mapCell.x, mapCell.y).conquered) {
                    replaceMapCell(mapCell.x, mapCell.y,  new MiniCannon_MapCell());

                }
                
            }*/
            Stats.terrainConquering(this);
        }
        

        /// <summary>
        /// Description.
        /// </summary>
        public void putWalls() {

            List<MapCell> tilesToCheck = new List<MapCell>();


            //const int OWNER_NOONE = -1;
            int x, y;
            

            // initial pass
            for (y = 0; y < Constant.TOTAL_TILES_Y; y++)
                for (x = 0; x < Constant.TOTAL_TILES_X; x++) {

                    //NO SE EVALUAN LAS QUE YA ESTABAN CONQUISTADAS
                    if (getMapCell(x,y).conquered) {
                        continue;
                    }

                    MapCell cell = firstCheck(x,y);

                    if (cell != null) {
                        tilesToCheck.Add(cell);
                    }

                    
                } // end initial pass


            secondCheck(tilesToCheck);

            Stats.terrainConquering(this);
            //paintDiferentsPlayer(player);
        }//end check conquer


        /*retorna la lista de las que falta ver que estado estan
         **/
        private MapCell firstCheck(int x, int y) {
            MapCell cell = getMapCell(x, y);
            
            
            //la evaluamos ahora por eso ponemos en chequed
            cell.chequed = true;

            // wall-tile. always conquered
            if (cell.isWall() && cell.player != null) {
                cell.conquered = true;
                return null;
            }

            // border-tile and not a wall => not conquered.
            if (y == 0 || x == 0 || y == Constant.TOTAL_TILES_Y - 1 || x == Constant.TOTAL_TILES_X - 1) {
                cell.conquered = false;
                cell.player = null;
                return null;
            }

            // Ok, this tile is not conquered, not checked yet, and is not a wall-tile.
            bool ok = true;

            // lets check all its adjacent tiles from west to north-east
            for (Direction dir = Direction.W; dir <= Direction.NE; dir++) {
                MapCell cellTemp = getMapCell(dir.getRelativeAbscissa(x), dir.getRelativeOrdinate(y));

                if (!cellTemp.conquered && cellTemp.chequed) {
                    ok = false;
                    break;
                }
            } // end dir-for


            if (!ok) {
                // we found adjacent checked and not conquered tile =>
                // this tile is not conquered.
                // if it was set as conquered before, it is changed
                if (cell.conquered) {
                    cell.conquered = false;
                    
                    //cell.player = null;

                    //replaceMapCell(x, y, new NotConquered_MapCell());cell.tileType = TileType.NOT_CONQUERED;
                    cell.change(TileType.NOT_CONQUERED);

                    //changedTiles.Add(cell);
                }

                return null;
            }

            //Sique aca cuando todo su izquierda y todo arriba esta conquistado
            // adjacent tiles are all ok, this tile should be checked (as S, SE, E, SW tiles not checked yet!)
            cell.x = x;
            cell.y = y;
            
            //cell.player = null;
            // if it was conquered before, check it
            if (cell.conquered) {
                
                cell.conquered = false;

                cell = cell.change(TileType.NOT_CONQUERED);
                //cell = replaceMapCell(x, y, new NotConquered_MapCell());cell.tileType = TileType.NOT_CONQUERED;
                //changedTiles.Add(cell);
            }

            cell.chequed = false;
            return cell;
        }

        private void secondCheck(List<MapCell> tilesToCheck) {
            int lastNroChecked = 1;
            int nroWillCheck = 0;
            Player owner = null;
            bool ok, ready;

            while (lastNroChecked != nroWillCheck) {
                int i = 0;
                lastNroChecked = nroWillCheck;
                nroWillCheck = tilesToCheck.Count();

                while (i < nroWillCheck) {
                    i++;

                    MapCell tempMapCell = tilesToCheck.First();
                    tilesToCheck.RemoveAt(0);

                    tempMapCell.chequed = true;

                    // Ok, this tile is not conquered, not checked yet, and is not a wall-tile
                    ok = true;
                    ready = true;

                    // lets check all its adjacent tiles
                    for (Direction dir = Direction.W; dir <= Direction.SW; dir++) {
                        MapCell tempMapCell2 = getMapCell(dir.getRelativeAbscissa(tempMapCell.x), dir.getRelativeOrdinate(tempMapCell.y));

                        if (!tempMapCell2.chequed) {
                            ready = false;
                            continue;
                        }

                        if (!tempMapCell2.conquered) {
                            ok = false;
                            break;
                        }

                        // conquer this to owner, if all goes ok
                        owner = tempMapCell2.player;

                    } // end dir-for

                    if (!ok) {
                        // we found adjacent checked and not conquered tile =>
                        // this tile is not conquered.
                        tempMapCell.conquered = false;
                        //tempMapCell.player = null;
                        //			  changed_tiles.push_back (coord (x, y));
                        continue;
                    }

                    if (!ready) {
                        // adjacent tiles are not ready, this tile should be checked next round
                        tilesToCheck.Add(tempMapCell);
                        tempMapCell.chequed = false;
                        continue;
                    }

                    // at this point the tile should belong to conquered tiles
                    //		  printf ("tile %d %d conquered to owner %d\n", c.x, c.y, owner);


                    tempMapCell.conquered = true;
                    //changedTiles.Add(tempMapCell);
                    
                    tempMapCell.player = owner;

                    //replaceMapCell(tempMapCell.x, tempMapCell.y, new Conquered_MapCell()); tempMapCell.tileType = TileType.PLAYER_CONQUERED;
                    tempMapCell.change(TileType.PLAYER_CONQUERED);

                } // end while
            } // end while

            //  printf ("%d tiles left unchecked\n", tilesToCheck.size());
            // ok, now all the tiles remaining at status "not checked" should be conquered tiles.
            while (tilesToCheck.Count() != 0) {
                MapCell cellTemp = tilesToCheck.First();
                tilesToCheck.RemoveAt(0);

                // this tile is not checked, so the tile north of it SHOULD be checked.
                MapCell northCell = getMapCell(cellTemp.x, cellTemp.y - 1);
                // assert (nt.checked);
                cellTemp.chequed = true;
                cellTemp.player = northCell.player;

                cellTemp.conquered = true;



                cellTemp.change(TileType.PLAYER_CONQUERED);
                //replaceMapCell(cellTemp.x, cellTemp.y, new Conquered_MapCell()); cellTemp.tileType = TileType.PLAYER_CONQUERED;
                //changedTiles.Add(cellTemp);
                //  printf ("final tile at %d %d owner %d, up type %d\n", c.x, c.y, nt.owner, nt.type);
            }
        }
    }


}